// Modelo Sistemas de recoleccion de piezas!!!
#include "simlib.c"
#include <cmath>
//Definicion de tipos de eventos
#define Generar		    1
#define Recolectar  	2
#define Descargar		3
//Definimos tipo de transfer para hacerlos mas claros
#define TiempoSim       1
#define Tevento         2
#define Maquina         3
//Definicion de constantes
#define Tsimulacion     7200      //Tiempo maximo de simulacion
#define MaquinaA        0
#define MaquinaB        1
#define MaquinaC        2
#define MaquinaD        3
#define Carro           5
#define ProduccionAB    0.200     //La produccion se mide en minutos (12/60)
#define ProduccionCD    0.333     // Piezas sobre minutos en 1 hora (20/60)
#define Interestacion   0.500       // 30 segundos, medio minuto (30/60)
#define Descarga        4.500       // 5 Minutos (Incluyendo los 30 segundos hasta estacion A)
#define MaxCarga        6
//Elementos usados para corridas:
#define corridas        25
#define indices         3
#define tstudent        2.0639
//Estadisticos
//Declaracion de variables
int StockCarro, maquina_actual, cantidad_pasadas, cantidad_descargas, contador, item;
int Piezas[4] = {1,2,3,3}; //Definimos tamano de piezas
int Stock[4] = {0,0,0,0}; //Definimos pilas de stock para las maquinas
float  porcentaje, cola, promedio, varianza, intervalo;
float datos[corridas][indices];

// Declaracion de nuestras funciones
void inicializa(void);
void RGenerar(void);
void RRecolectar(void);
void RDescargar(void);
void reporte(void);
void guardar_corrida(void);
void analizar_datos(void);

//Inicio de simulacion
main()
{
 printf( "Inicializacion de la simulacion... \n");
 printf( "__________________________________ \n");
 for(contador=1;contador<corridas;contador++)
 {
    printf( "Corrida numero %i. \n", contador);
    init_simlib();                      // Initializar Simlib
	maxatr = 3;                         // Establecer maxatr = M ximo n£mero de Atributos utilizados
	cantidad_pasadas = 0;
	cantidad_descargas = 0;
    inicializa();                       // Initializa los parametros de la simulacion
	while (sim_time < Tsimulacion) //Mientras el tiempo actual no complete lo que se desea simular
	{
        timing(); //Buscar proximo evento
		switch( next_event_type ) //Determinamos que tipo de evento sera!
		{   case Generar: 
            {    RGenerar(); //Si el evento es una pieza generada     
                 break;
            }
			case Recolectar: 
            {    RRecolectar(); //Si el evento es una pieza recolectada
                 break;
            }
			case Descargar: 
            {    RDescargar(); //Si el evento es una descarga del carrito
                 break;
            }            
        }
	}	
	guardar_corrida();
 }	
 reporte();
 analizar_datos();
 }

void inicializa(void)// Initializamos los parametros de la simulacion
{
    //generar la primer pieza en cada maquina
    //Maquina A
	transfer[TiempoSim] = sim_time + expon(ProduccionAB,1); //Calcula el tiempo en que generar la primer pieza
    transfer[Tevento] = Generar; //Carga el tipo de evento
	transfer[Maquina] = MaquinaA; //Definimos a que maquina pertenece el evento
    list_file(INCREASING,LIST_EVENT);
	//Maquina B
	transfer[TiempoSim] = sim_time + expon(ProduccionAB,1);
	transfer[Tevento] = Generar;
	transfer[Maquina] = MaquinaB;
	list_file(INCREASING,LIST_EVENT);
	//Maquina C
	transfer[TiempoSim] = sim_time + expon(ProduccionCD,1);
	transfer[Tevento] = Generar;
	transfer[Maquina] = MaquinaC;
	list_file(INCREASING,LIST_EVENT);
	//Maquina D
	transfer[TiempoSim] = sim_time + expon(ProduccionCD,1);
	transfer[Tevento] = Generar;
	transfer[Maquina] = MaquinaD;
	list_file(INCREASING,LIST_EVENT);
	//generamos la primera recoleccion de piezas
	transfer[TiempoSim] = sim_time + Interestacion;
	transfer[Tevento] = Recolectar;
	transfer[Maquina] = MaquinaA;
	list_file(INCREASING,LIST_EVENT);
}

void RGenerar(void)  // Evento de generacion de pieza
{
    // Determinar la proxima pieza generada
	maquina_actual = transfer[Maquina];
    if ((transfer[Maquina] == MaquinaA) or (transfer[Maquina] == MaquinaB))
        transfer[TiempoSim] = sim_time + expon(ProduccionAB,1);
    else
        transfer[TiempoSim] = sim_time + expon(ProduccionCD,1);
    transfer[Tevento] = Generar;
	transfer[Maquina] = transfer[Maquina];
	list_file(INCREASING,LIST_EVENT);
	
    //Incrementamos el stock en la cola de la maquina actual
	transfer[1] = sim_time; //cargamos el tiempo para determinar la demora cdo lo sacamos de la lista
    list_file(LAST, maquina_actual + 1); 
}

void RRecolectar(void)  /* Evento de inventario */
{
    maquina_actual = (int)transfer[Maquina]; //numero de la maquina que sera utilizado luego
    //Avanzamos carrito
    if (transfer[Maquina] == MaquinaD)
        {
            cantidad_pasadas++;
            if (StockCarro < (MaxCarga/2)) //Si hay mas de 50% libre (Solo 2 lugares ocupados)
            {
                printf("nooooooooooooooooo");
                transfer[TiempoSim]= sim_time + Interestacion;
                transfer[Tevento]= Recolectar;
                transfer[Maquina]= MaquinaA;
            }
            else
            {
                cantidad_descargas++;
                transfer[TiempoSim]= sim_time + Descarga;
                transfer[Tevento]= Descargar;
            }
        }
    else
        {
            transfer[TiempoSim]= sim_time + Interestacion;
            transfer[Tevento]= Recolectar;
            transfer[Maquina]++;
            
        }
	list_file(INCREASING,LIST_EVENT);
	//Inteta Recolectar piezas
    while ((list_size[maquina_actual + 1] != 0) and ((MaxCarga - StockCarro) >= Piezas[maquina_actual]))
	{
          StockCarro = StockCarro + Piezas[maquina_actual];
          list_remove(LAST, maquina_actual + 1);
          sampst(sim_time - transfer[1], maquina_actual + 1);
          list_file(FIRST, Carro); //incrementa una unidad en el carro
     }
 }

void RDescargar(void) //Descargamos piezas
{
    StockCarro= 0; //Descargamos el carro
	transfer[TiempoSim]= sim_time + Interestacion;
	transfer[Tevento]= Recolectar;
    transfer[Maquina]= MaquinaA;
    list_file(INCREASING,LIST_EVENT);
    while (list_size[Carro] != 0)
          list_remove(FIRST, Carro);      
}

void guardar_corrida(void) //llevaremos solo los estadisticos del a maquina A, por que es inutil mas.
{
 cola = filest(MaquinaA);
 sampst(0, -1);
 datos[contador][1]= transfer[1];
 datos[contador][2]= transfer[3];
 datos[contador][3]= cola;
}

void analizar_datos(void)
{
  for (item=1;item<3;item++)
  {
     promedio= 0;
     for (contador=1;contador<corridas;contador++)
     {
         promedio+= datos[contador][item];
     }
     promedio/=corridas;
     varianza=0;
     for (contador=1;contador<corridas;contador++)
     {
         varianza+= (datos[contador][item] - promedio) * (datos[contador][item] - promedio);
     }
     varianza/=corridas;
     intervalo= tstudent * sqrt(varianza / corridas);
  } 
}

void reporte( void )  /* Generar Reporte de la Simulaci¢n */
{
	/* -------- Por pantalla -------- */
    printf("Resultados de la simulacion del sistema de Produccion \n");
	cola = filest(MaquinaA);
    sampst(0, -1);	
    printf("Maquina A: \n Demora media: %10.3f \n Demora maxima %f \n Numero promedio en cola %f \n\n", transfer[1], transfer[3], cola);
    cola = filest(MaquinaB);
    sampst(0, -2); 
    printf("Maquina B: \n Demora media: %10.3f \n Demora maxima %f \n Numero promedio en cola %f \n\n", transfer[1], transfer[3], cola);
    cola = filest(MaquinaC);
    sampst(0, -3); 
    printf("Maquina C: \n Demora media: %10.3f \n Demora maxima %f \n Numero promedio en cola %f \n\n", transfer[1], transfer[3], cola);
    cola = filest(MaquinaD);
    sampst(0, -4); 
    printf("Maquina D: \n Demora media: %10.3f \n Demora maxima %f \n Numero promedio en cola %f \n\n", transfer[1], transfer[3], cola);
    porcentaje = (float)cantidad_descargas/(float)cantidad_pasadas;
    printf("Porcentaje de vuelta grande: %10.3f % \n", (1 - porcentaje)*100);
    printf("Cantidad media de piezas transportadas en el carro: %10.3f \n", filest(Carro));
    printf( "___________________________________ \n");
    
    system("pause");
}
